using System;
using CommonDomain.Persistence;

namespace Sponsorship.Domain.Payments
{
    /// <summary>
    /// Handles domain commands dealing with <see cref="Payment"/> instances.
    /// </summary>
    public class PaymentCommandHandler :
        ICommandHandler<EnterPayment>,
        ICommandHandler<ChangePayment>,
        ICommandHandler<DeletePayment>,
        ICommandHandler<EnterAnonymousPayment>,
        ICommandHandler<DisassociatePayment>,
        ICommandHandler<AssociateAnonymousPayment>
    {
        private readonly IRepository _repository;

        public PaymentCommandHandler (IRepository repository)
        {
            _repository = repository;
        }

        public void Handle (EnterPayment command)
        {
            Payment payment = Payment.EnterPayment (command.PaymentId, command.SponsorId, command.Amount, command.DateTime, command.BankInformation, command.Text, command.Comment);

            //save new raised events of aggregate into eventstore
            SavePayment (payment);
        }

        public void Handle (ChangePayment command)
        {
            Payment payment = LoadPayment (command.PaymentId, command.Version);

            //execute domain logic and get back a new aggregate
            payment.Change (command.Amount, command.DateTime, command.BankInformation, command.Text, command.Comment);

            //save new raised events of aggregate into eventstore
            SavePayment (payment);
        }

        public void Handle (DeletePayment command)
        {
            Payment payment = LoadPayment (command.PaymentId, command.Version);

            //execute domain logic and get back a new aggregate
            payment.Delete();

            //save new raised events of aggregate into eventstore
            SavePayment (payment);
        }

        public void Handle (EnterAnonymousPayment command)
        {
            Payment payment = Payment.EnterAnonymousPayment (command.PaymentId, command.Amount, command.DateTime, command.BankInformation, command.Text, command.Comment);

            //save new raised events of aggregate into eventstore
            SavePayment (payment);
        }

        public void Handle (AssociateAnonymousPayment command)
        {
            Payment payment = LoadPayment (command.PaymentId, command.Version);

            //execute domain logic and get back a new aggregate
            payment.Associate (command.SponsorId);

            //save new raised events of aggregate into eventstore
            SavePayment (payment);
        }

        public void Handle (DisassociatePayment command)
        {
            Payment payment = LoadPayment (command.PaymentId, command.Version);

            //execute domain logic and get back a new aggregate
            payment.Disassociate();

            //save new raised events of aggregate into eventstore
            SavePayment (payment);
        }

        private Payment LoadPayment (Guid guid, int version)
        {
            return _repository.GetById<Payment> (guid, version);
        }

        private void SavePayment (Payment sponsorship)
        {
            _repository.Save (sponsorship, Guid.NewGuid()); // Every commit has a new ID
        }
    }
}